﻿/* -----------------------------------------------------------------------------
 * Copyright (c) 2019-2021 linling
 *
 * 本软件"按原样"提供，没有任何明示或暗示的保证。 在任何情况下，作者均
 * 不对因使用本软件而导致的任何损害承担责任。 允许任何人将本软件用于
 * 任何目的（包括商业应用程序），并对其进行更改并自由重新分发，但受以下限制：
 *
 * 1.不得歪曲本软件的来源; 你不能声称你写了原始软件。
 *   如果你在产品中使用此软件，在产品文档中的承认将不胜感激，但不是必需的。
 *
 * 2.更改的源版本必须明确标记，不得歪曲为原始软件。
 *
 * 3.不得从任何来源分发中删除或更改此通知。
 */
#ifndef __MODBUS_TCP2RTU_H
#define __MODBUS_TCP2RTU_H

#include "mbed.h"
#include "xos2.h" 
#include "api.h" 
#include "net.h" 
#include "qSocket.hpp"
#include <vector>


/// <summary>
/// 服务端,侦听指定的端口,可配置为接受多个连接
/// </summary>
class ModbusTcp2RtuServer {
public:

	/// <summary>
	/// 构造函数,指定RS485引脚以及服务端口号,注意:会自动启动侦听
	/// </summary>
	/// <param name="tx">指定RS485发送数据引脚名,按串行端口</param>
	/// <param name="rx">指定RS485接收数据引脚名,按串行端口</param>
	/// <param name="ctrl">指定RS485半双工方向控制引脚名</param>
	/// <param name="_port">指定服务端口号</param>
	/// <param name="_backlog">可指定最大连接数,默认为1</param>
	ModbusTcp2RtuServer(PinName tx, PinName rx, PinName ctrl, int _port, int _backlog = 1);

	/// <summary>
	/// 初始化可供客户端读写的寄存器,如果工作在纯转发模式,则无需调用本函数
	/// </summary>
	/// <param name="_nodeaddr">指定节点地址</param>
	/// <param name="_Regs">指定可供读写的缓冲区</param>
	/// <param name="cnt">指定可供读写的缓冲区个数,不是字节数</param>
	void Init(int _nodeaddr, uint16* _Regs, uint16_t cnt);

	/// <summary>
	/// 应周期调用的任务函数,响应客户端的请求,支持本机服务,节点地址不同时转发到RTU,需要调用初始化寄存器的函数
	/// </summary>
	/// <param name="delay">是否启用内部延迟</param>
	void Task(bool delay = true);

	/// <summary>
	/// 应周期调用的任务函数,处理纯转发到RTU的任务
	/// </summary>
	/// <param name="delay">是否启用内部延迟</param>
	void Task2RTU(bool delay = true);

	/// <summary>
	/// 存储可供读取的地址区间,高16位表示起始地址,低16位表示结束地址,默认全范围
	/// </summary>
	std::vector<uint32_t> readableList;
	/// <summary>
	/// 存储可供写入的地址区间,高16位表示起始地址,低16位表示结束地址,默认全范围
	/// </summary>
	std::vector<uint32_t> writableList;

	/// <summary>
	/// 设置RS485总线的速率
	/// </summary>
	/// <param name="b">波特率</param>
	void SetBaudrate(int b);

	bool Debug;
private:
	int Baudrate;
	qSerialPort  SerialPort;
	DigitalOut   rs485ctrl;

	uint16* Regs;
	int RegsCount;
	int NodeAddress;
	qSocketServer sock;

	byte rxbuff[256 + 16];
	TimeLoop t;

	bool Readable(int regaddr, int regcnt);
	bool Writable(int regaddr, int regcnt);
	int ToRtu(byte* buff,int len,int waitlen);
	void RtuSend(byte* buf, int len);
};
#endif
